/**
 * Project Name:ccopsgw
 * File Name:SgipQdServer.java
 * Package Name:com.ccop.sgw.sgipqd.socket
 * Date:2016年4月1日下午6:37:15
 * Copyright (c) 2016, LiHao All Rights Reserved.
 *
*/

package com.cloud.demo.smgp;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Date;

import org.apache.commons.lang.StringUtils;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.transport.socket.SocketSessionConfig;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.cloud.demo.smgp.msg.SmgpMsgDeliver;
import com.cloud.demo.smgp.msg.SmgpMsgHead;
import com.cloud.demo.smgp.msg.SmgpMsgLoginResp;
import com.cloud.demo.smgp.msg.SmgpMsgSubmitResp;
import com.cloud.demo.smgp.msg.SmgpTlv;
import com.cloud.demo.utils.ByteConvert;
import com.cloud.demo.utils.DateUtils;
import com.cloud.demo.utils.MsgUtils;



/**
 * ClassName:SgipQdServer <br/>
 * Function: TODO ADD FUNCTION. <br/>
 * Reason:	 TODO ADD REASON. <br/>
 * Date:     2016年4月1日 下午6:37:15 <br/>
 * @author   LiHao
 * @version  
 * @since    JDK 1.6
 * @see 	 
 */
public class SmgpServer extends IoHandlerAdapter {
	private static Logger logger = LoggerFactory.getLogger(SmgpServer.class);
	private String socketPort = "8890";
	private static SmgpServer _instance;
	private NioSocketAcceptor acceptor=null;
	private InetSocketAddress socketAddres = null;  

	/**
	 * 当接口中其他方法抛出异常未被捕获时触发此方法
	 */
	public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
		String clientIP = ((InetSocketAddress) session.getRemoteAddress()).getAddress().getHostAddress();
		logger.warn("exceptionCaught:", cause.getMessage()+",clientIP:" + clientIP);
//		this.removeUserBySessionId(session);
		cause.printStackTrace();
//		session.close(true);
	}

	/**
	 * 当接收到客户端的信息
	 */
	public void messageReceived(IoSession session, Object message) throws Exception {
		String clientIP = ((InetSocketAddress) session.getRemoteAddress()).getAddress().getHostAddress();
		logger.debug("服务器接收到client:{}的数据： {}", new Object[]{clientIP,message});
		byte[] inByte = (byte[]) message;
		byte [] headBytes = new byte[SmgpCommand.MsgHeaderLength];
		byte totalLenBytes[]=new byte[SmgpCommand.MsgTotalLength];
		byte commandIdBytes[]=new byte[SmgpCommand.MsgRequestId];
		byte sequenceIdBytes[]=new byte[SmgpCommand.MsgSequenceId];
		System.arraycopy(inByte, 0, headBytes, 0, SmgpCommand.MsgHeaderLength);
		System.arraycopy(headBytes, 0, totalLenBytes, 0, 4);
		System.arraycopy(headBytes, 4, commandIdBytes, 0, 4);
		System.arraycopy(headBytes, 8, sequenceIdBytes, 0, 4);
		int totalLen=ByteConvert.bytesToInt(totalLenBytes);
		byte bodyBytes[]=new byte[totalLen-SmgpCommand.MsgHeaderLength];
		if(bodyBytes.length>0){
		System.arraycopy(inByte, SmgpCommand.MsgHeaderLength, bodyBytes, 0, bodyBytes.length);
		}
//		String sequenceId=ByteConvert.getStr(sequenceIdBytes)
		int sequenceId=ByteConvert.bytesToInt(sequenceIdBytes);;
		int commandId=ByteConvert.bytesToInt(commandIdBytes);
		switch(commandId){
			case SmgpCommand.CMD_SMGP_LOGIN:
				logger.debug("【Smgp】收到SMG ->Login命令");
				SmgpMsgLoginResp loginResp=new SmgpMsgLoginResp();
				loginResp.setPacketLength(12+4+16+1);
				loginResp.setRequestId(SmgpCommand.CMD_SMGP_LOGIN_RESP);
				loginResp.setSequenceId(sequenceId);
				loginResp.setStatus(0);
				loginResp.setVersion((byte)1);
				byte[] authenticatorServer=new byte[16];
				loginResp.setAuthenticatorServer(authenticatorServer);
				this.send(session, loginResp.toByteArry());
				break;
			case SmgpCommand.CMD_SMGP_ACTIVE_TEST:
				logger.debug("【Smgp】收到SMG ->ActiveTest命令");
				SmgpMsgHead msgActiveResp=new SmgpMsgHead();
				msgActiveResp.setPacketLength(totalLen);
				msgActiveResp.setRequestId(SmgpCommand.CMD_SMGP_ACTIVE_TEST_RESP);
				msgActiveResp.setSequenceId(sequenceId);
				this.send(session, msgActiveResp.toByteArry());
				
				break;
			case SmgpCommand.CMD_SMGP_SUBMIT:
				logger.debug("【Smgp】收到SMG ->submit命令");
				String msgId="msgId"+this.getSequence()+"";
				SmgpMsgSubmitResp submitResp=new SmgpMsgSubmitResp();
				submitResp.setPacketLength(12+10+4);
				submitResp.setRequestId(SmgpCommand.CMD_SMGP_SUBMIT_RESP);
				submitResp.setSequenceId(sequenceId);
				submitResp.setMsgId(msgId);
				submitResp.setStatus(0);
				this.send(session, submitResp.toByteArry());
				
				SmgpMsgDeliver deliver=new SmgpMsgDeliver();
				int reportLen=10+3+3+10+10+7+3+20;
				int reportSplitLen=3+5+7+13+11+6+5+6;
				deliver.setPacketLength(12+10 + 1 + 1 + 14 + 21 + 21 + 1 + 8+reportLen+reportSplitLen);
				deliver.setRequestId(SmgpCommand.CMD_SMGP_DELIVER);
				deliver.setSequenceId(getSequence());
				String rMsgId="repId"+getSequence()+"";
				deliver.setsMsgID(rMsgId);
				deliver.setcIsReport((byte)1);
				deliver.setUcMsgFormat((byte)15);
				deliver.setsRecvTime(DateUtils.formatMdhmsDate(new Date()));
				deliver.setsSrcTermID("12520007312");
				deliver.setsDestTermID("10000000");
				deliver.setUcMsgLength((byte)(reportLen+reportSplitLen));
				
				deliver.setMsg_Id_report(msgId);
				deliver.setSub("001");
				deliver.setVrd("001");
				deliver.setSubmit_time(DateUtils.formatDate(new Date(), "yyMMddHHmm"));
				deliver.setDone_time(DateUtils.formatDate(new Date(), "yyMMddHHmm"));
				deliver.setStat("DELIVRD");
				deliver.setErr("000");
				deliver.setTxt("");
				
				deliver.setsReserve("");
				
				
				ByteArrayOutputStream bous=new ByteArrayOutputStream();
				DataOutputStream dous=new DataOutputStream(bous);
				try {
					dous.writeInt(deliver.getPacketLength());
					dous.writeInt(deliver.getRequestId());
					dous.writeInt(deliver.getSequenceId());
					MsgUtils.writeString(dous,deliver.getsMsgID(),10);
					dous.writeByte(deliver.getcIsReport());
					dous.writeByte(deliver.getUcMsgFormat());
					MsgUtils.writeString(dous,deliver.getsRecvTime(),14);
					MsgUtils.writeString(dous,deliver.getsSrcTermID(),21);
					MsgUtils.writeString(dous,deliver.getsDestTermID(),21);
					dous.writeByte(deliver.getUcMsgLength());
					MsgUtils.writeString(dous,"id:",3);
					MsgUtils.writeString(dous,deliver.getMsg_Id_report(),10);
					MsgUtils.writeString(dous," sub:",5);
					MsgUtils.writeString(dous,deliver.getSub(),3);
					MsgUtils.writeString(dous," dlvrd:",7);
					MsgUtils.writeString(dous,deliver.getVrd(),3);
					MsgUtils.writeString(dous," Submit date:",13);
					MsgUtils.writeString(dous,deliver.getSubmit_time(),10);
					MsgUtils.writeString(dous," done date:",11);
					MsgUtils.writeString(dous,deliver.getDone_time(),10);
					MsgUtils.writeString(dous," stat:",6);
					MsgUtils.writeString(dous,deliver.getStat(),7);
					MsgUtils.writeString(dous," err:",5);
					MsgUtils.writeString(dous,deliver.getErr(),3);
					MsgUtils.writeString(dous," Text:",6);
					MsgUtils.writeString(dous,deliver.getTxt(),20);
					
					MsgUtils.writeString(dous,deliver.getsReserve(),8);
					
					dous.close();
					
				} catch (IOException e) {
					logger.error("smgp封装短信发送二进制数组失败。");
				}
				this.send(session, bous.toByteArray());
				
				
//				Thread.sleep(1000);
				
				break;
			case SmgpCommand.CMD_SMGP_DELIVER_RESP:
				logger.debug("【Smgp】收到SMG ->DeliverResp命令");
				
				break;
			default:
				logger.error("【smgp无法解析SMG返回的包结构】包长度为:"+totalLen+",commandId:"+commandId);
				break;
		}
		
	}
	private static int sequenceId=1;//序列编号
	public synchronized static int getSequence(){
		++sequenceId;
		if(sequenceId>=1000000){
			sequenceId=1;
		}
		return sequenceId;
	}
	/**
	 * 客户端关闭
	 */
	public void sessionClosed(IoSession session) throws Exception {
		String clientIP = ((InetSocketAddress) session.getRemoteAddress()).getAddress().getHostAddress();
		
		logger.info("客户端关闭sessionClosed,clientIP:" + clientIP);
		
	}
	
	/**
	 * 当一个新客户端连接后触发此方法
	 */
	public void sessionCreated(IoSession session) throws Exception {
		String clientIP = ((InetSocketAddress) session.getRemoteAddress()).getAddress().getHostAddress();
		logger.info("有新客户端连接sessionCreated,clientIP:" + clientIP);
	}

	/**
	 * 当连接空闲时触发此方法
	 */
	public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
		String clientIP = ((InetSocketAddress) session.getRemoteAddress()).getAddress().getHostAddress();
		
		logger.info("客户端连接闲置sessionIdle,clientIP:" + clientIP);
		session.closeNow();
	}

	/**
	 * 当一个客户端连接进入时
	 */
	public void sessionOpened(IoSession session) throws Exception {
		String clientIP = ((InetSocketAddress) session.getRemoteAddress()).getAddress().getHostAddress();
		logger.info("客户端连接成功sessionOpened,clientIP:" + clientIP);
		
	}

	public SmgpServer() throws IOException {
//		NioSocketAcceptor acceptor = new NioSocketAcceptor();
		acceptor = new NioSocketAcceptor();
		acceptor.getFilterChain().addLast("codec",
				new ProtocolCodecFilter(new DefaultMinaCodecFactory(new FEncoder(), new FDecoder())));
		acceptor.setHandler(this);
		SocketSessionConfig scfg = acceptor.getSessionConfig();
		scfg.setTcpNoDelay(true);
		scfg.setReadBufferSize(2048);
		scfg.setIdleTime(IdleStatus.BOTH_IDLE, 20);
		scfg.setSoLinger(0); 
		scfg.setWriteTimeout(10);   //调整超时时间
		scfg.setKeepAlive(true);    //是否保持长连接
		if(StringUtils.isNotBlank(socketPort)){
			socketAddres=new InetSocketAddress(Integer.parseInt(socketPort));
			acceptor.bind(socketAddres);
			logger.info("【smgp】 mina服务启动完成,port:"+socketPort);
		}else{
			logger.warn("socketPort 未配置");
		}
	}

	synchronized public static SmgpServer getInstance() {
		if (null == _instance) {
			logger.info("【smgp】-------启动mina服务----------");
			try {
				_instance = new SmgpServer();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return _instance;
	}

	public void send(IoSession session, byte dateBuf[]) {
		try {
			session.write(dateBuf);
		} catch (Exception e) {
			logger.error("发送消息异常" + e.getMessage());
			e.printStackTrace();
		}
	}
	
	public void closeSocketServer() {
		//方法释放资源
		logger.info("【smgp】关闭mina服务");
		if (null!=acceptor) {  
            acceptor.unbind(socketAddres);  
            acceptor.getFilterChain().clear();  // 清空Filter chain，防止下次重新启动时出现重名错误  
            acceptor.dispose();                 // 可以另写一个类存储IoAccept，通过spring来创建，这样调用dispose后也会重新创建一个新的。或者可以在init方法内部进行创建。  
            acceptor = null;  
        }  
	}
	
	public static void main(String[] args) {
		SmgpServer.getInstance();
	}
}

